package cn.jtool.dig.common.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.Lifecycle;
import org.springframework.context.SmartLifecycle;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

public class TcpServer implements SmartLifecycle, BeanNameAware {
    private static final Logger LOG = LoggerFactory.getLogger(TcpServer.class);
    private final ServerBootstrap serverBootstrap;
    /**
     * 监听请求线程组
     */
    private final EventLoopGroup acceptorGroup;
    /**
     * 处理客户端任务线程组
     */
    private final EventLoopGroup clientGroup;
    private volatile boolean started;
    private ChannelFuture channel;
    private String beanName;

    private final String host;

    private final int port;


    public TcpServer(String name, String host, int port, ChannelHandler channelHandler) {
        this.beanName = name;
        this.host = host;
        this.port = port;
        this.serverBootstrap = new ServerBootstrap();
        this.acceptorGroup = new NioEventLoopGroup();
        this.clientGroup = new NioEventLoopGroup();
        this.serverBootstrap.channel(NioServerSocketChannel.class);
        this.serverBootstrap.group(this.acceptorGroup, this.clientGroup);
        this.serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
        this.serverBootstrap.option(ChannelOption.SO_KEEPALIVE, true);
        this.serverBootstrap.childHandler(channelHandler);
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void start() {
        if(!this.started) {
            try {
                InetAddress addr = InetAddress.getByName(host);
                channel = serverBootstrap.bind(new InetSocketAddress(addr, port)).sync();
            } catch (Exception e) {
                LOG.error("Unable to start TCP server {}, {}:{}", this.beanName, this.host, this.port, e);
                started = false;
                return;
            }

            LOG.info("Server '{}' started on {}:{}", beanName, this.host, this.port);
            started = true;
        }else{
            LOG.warn("服务 {} {}:{} 已启动", this.beanName, this.host, this.port);
        }
    }

    @Override
    public void stop() {
        if (!started) {
            return;
        }
        try {
            this.channel.channel().close();
        } catch (Exception e) {
            LOG.warn("Unable to stop server '" + beanName + "'", e);
        } finally {
            this.clientGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
            this.acceptorGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
        }
    }

    @Override
    public boolean isRunning() {
        return started;
    }

    @Override
    public boolean isAutoStartup() {
        return true;
    }
}
